package cn.good.yan.controller;

import cn.good.yan.apis.PayFeignApi;
import cn.good.yan.resp.ResultData;
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 订单 - 演示：Resilience4j  feign的远程调用
 * 演示：
 * 启动 cloud-order、cloud-provider-payment 服务
 * 常见的限流算法：
 * 1.漏洞算法
 * 2.令牌桶算法
 * 3.滚动时间窗
 * 4.滑动时间窗
 *
 * @author shengren.yan
 * @create 2022-04-06
 */
@RestController
public class OrderController {

    // Feign 接口
    @Autowired
    private PayFeignApi payFeignApi;

    // --------------  远程调用 -------------------
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "/test1")
    public ResultData<String> test1() {
//        String name = restTemplate.getForObject("http://cloud-provider-payment/rescire1" , String.class);
        String name = payFeignApi.rescire1();
        return ResultData.success("远程调用，返回值: " + name);
    }

    /**
     * 演示1 - 远程调用接口 - 服务的降级配置
     * 对应的配置文件在： Resilience4j CircuitBreaker的配置
     * 远程调用请求： http://localhost:8001/rescire/1   （会请求成功）
     * 远程调用 请求： http://localhost:8001/rescire/-4  （会报错 - 提示：id 不能负数），但多次请求失败，会触发断路器，执行myCircuitFallback（）里逻辑
     * 多次请求 -4 错误的请求，会触发服务降级，执行myCircuitFallback（）方法里逻辑，
     * 熔断配置，在配置文件 -  resilience4j 这里配置
     *
     * @param id
     * @return {@link ResultData}<{@link String}>
     */
    @GetMapping(value = "/test/{id}")
    @CircuitBreaker(name = "cloud-p", fallbackMethod = "myCircuitFallback")
    public String getPaymentById(@PathVariable("id") Integer id) {
        String name = payFeignApi.myCircuit(id);
        return name;
    }

    // 服务降级 - 执行这里的逻辑
    public String myCircuitFallback(Integer id, Throwable t) {
        System.out.println("服务降级的路径--------------");
        // 这里是容错处理逻辑，返回备用结果
        return "系统繁忙，请稍后再试-----/(ㄒoㄒ)/~~";
    }

    /**
     * 演示2 - 远程调用接口 - 最大并发限制 - 实现方式1：类型：Type.SEMAPHORE
     * 对应的配置文件在： Resilience4j bulkhead 的配置 1
     * 请求： http://localhost:8001/rescire2/1   （会请求成功）
     * 请求： http://localhost:8001/rescire2/9999  （耗时时间长，超过配置所设置的并发数，一直有任务在处理
     * 导致并没有处理完，新的正常的请求，（xxx//rescire2/1 ）请求会被限制，进行 test2Fallback（）里逻辑
     *
     * @param id
     * @return {@link ResultData}<{@link String}>
     */
    @GetMapping(value = "/test2/{id}")
    @Bulkhead(name = "cloud-p", fallbackMethod = "test2Fallback", type = Bulkhead.Type.SEMAPHORE)
    public String test2(@PathVariable("id") Integer id) {
        String name = payFeignApi.myCircuit2(id);
        return name;
    }

    // 服务降级 - 执行这里逻辑 - 达到最大的并发，执行这里逻辑
    public String test2Fallback(Integer id, Throwable t) {
        return "test2Fallback，隔板超出最大数量限制，系统繁忙，请稍后再试";
    }

    /**
     * 演示3 - 远程调用接口 - 最大并发限制 - 实现方式2: 线程池 THREADPOOL
     * 对应的配置文件在： Resilience4j bulkhead 的配置 2 - 线程池  - 与上面的配置一样，test2
     * 请求： http://localhost:8001/rescire2/1   （会请求成功）
     * 请求： http://localhost:8001/rescire2/9999  （耗时时间长，超过配置所设置的并发数，一直有任务在处理
     * 导致并没有处理完，新的正常的请求，（xxx//rescire2/1 ）请求会被限制，进行 test2Fallback（）里逻辑
     * 实现方式2：类型：Type.THREADPOOL
     *
     * @param id
     * @return {@link ResultData}<{@link String}>
     */
    @GetMapping(value = "/test3/{id}")
    @Bulkhead(name = "cloud-p", fallbackMethod = "test3Fallback", type = Bulkhead.Type.THREADPOOL)
    public CompletableFuture<String> test3(@PathVariable("id") Integer id) {
        System.out.println(Thread.currentThread().getName() + "\t" + "---开始进入");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "---准备离开");
        return CompletableFuture.supplyAsync(() -> payFeignApi.myCircuit2(id) + "\t" + "Bulkhead.线程池");
    }

    // 服务降级 - 执行这里逻辑 - 达到最大的并发，执行这里逻辑
    public CompletableFuture<String> test3Fallback(Integer id, Throwable t) {
        return CompletableFuture.supplyAsync(() -> "Bulkhead.Type.线程池,系统繁忙，请稍后再试");
    }

    /**
     * 演示4 - 远程调用接口 - 限流
     * 对应的配置文件在： Resilience4j ratelimiter 的配置
     * 请求： http://localhost:8001/rescire3/1   （会请求成功）
     * 请求： http://localhost:8001/rescire3/1  （多次点击，同一个请求，会被限流，执行test4Fallback（）这里逻辑
     *
     * @param id
     * @return {@link ResultData}<{@link String}>
     */
    @GetMapping(value = "/test4/{id}")
    @RateLimiter(name = "cloud-p", fallbackMethod = "test4Fallback")
    public String myBulkhead(@PathVariable("id") Integer id) {
        return payFeignApi.myCircuit3(id);
    }

    // 服务限流 - 执行这里逻辑
    public String test4Fallback(Integer id, Throwable t) {
        return "你被限流了，禁止访问";
    }


}
